interface IEnumerable<T>
{
	T GetItem(int id);
	void AddItem(T item);
}

interface GridContainer<indexType, itemType>
{
	IEnumerable<T> GetItem(indexType index);
	IEnumerable<int2> GetGrid();
	void AddItem(indexType idx, T item);
}

concept void MassiveClassify<indexType,itemType>(GridContainer<indexType, itemType> grid, IEnumerable<itemType> items, Func<itemType,indexType, bool> classifier);

implementation void Scatter<T1,T2>:MassiveClassify<T1,T2>(GridContainer<indexType, itemType> grid, IEnumerable<T2> items, Func<itemType,indexSetType> classifier)
{
	var gridIndices = grid.GetGrid();
	parallel foreach(var idx in gridIndices)
	{
		foreach(var item in items)
		{
			if (classifier(item).Contains(idx))
				grid.AddItem(idx, item);
		}
	}
}

implementation void Gather<T1,T2>:MassiveClassify<T1,T2>(GridContainer<indexType, itemType> grid, IEnumerable<T2> items, Func<itemType,indexType, bool> classifier)
{
	var gridIndices = grid.GetGrid();
	parallel foreach(var item in items)
	{
		foreach(var idx in item.GetOverlappingSamples(grid))
		{
			grid.AddItem(idx, item);
		}
	}
}

concept IndexSet OverlapClassifier(Triangle tri);

implementation void Gather<T1,T2>:MassiveClassify<T1,T2>(IEnumerable<T1> categories, IEnumerable<T2> items2, OverlapClassifier classifier)
{

}

implementation void SortClassify<T1,T2>:MassiveClassify<T1,T2>(SortedBin<indexType, itemType> grid, IEnumerable<T2> items, OverlapClassifier classifier) // auto choosing classifier
{
	grid.idxPairs = items.MapMany(item =>
	{
		foreach (var idx in classifier(item))
			yield return Tuple(idx, item);
	}).Flatten().Sort((t1,t2)=>t1.idx < t2.idx);
	grid.groups = grid.idxPairs.ScanAndGroup((i1,i2)=>i1!=i2);
}

class GridQueue<T> : GridContainer2D<T>
{
	List<Queue> queues;
	void SetSize(int w, int h)
	{
		queues.SetSize(w*h);
	}
	
}

class SortQueue<T> : GridContainer2D<T>
{
	
}

interface IndexSet
{
	int GetCount();
	Index GetIdx(int id);
	bool Contains(int2 idx);
}

class EnumerableIndexSet : IndexSet
{
	// implement everything
}

class PredicateIndexSet : IndexSet
{
	// only implement Contains();
}

implementation EnumerableIndexSet:OverlapClassifier(tri)
{
}
implementation PredicateIndexSet:OverlapClassifier(tri)
{
}

out int32 zbuffer[SIZE];
out int32 frameBuffer[SIZE];
in List<Triangle> triangles;
setupTriangles = triangles.MapMany(mapManyConfig, tri=>
{
  yield return TransformAndCull(tri);
});
bins = setupTriangles.MassiveClassify(massiveConfig, (tri)=>
{
  foreach (cell in OverlappedCells(tri))
     tag(tri, cell.id);
});
bins.Map(mapConfig, (bin) =>
{
  return bin.MassiveClassify(tileConfig, (tri)=>
  {
     foreach (cell in OverlappedCells(tri))
         tag(tri, cell.id)
  });
}).MapMany(mapConfig1, (cell)=>
{
  foreach (tri in cell)
     yield return FineRasterizeLookup(tri);
}).ParallelForEach(launchConfig, (frag)=>
{
  atomic(zbuffer[frag.coord])
  {
     if (zbuffer[frag.coord] > frag.z)
         zbuffer[frag.coord] = frag.z;
         frameBuffer[frag.coord] = Shade(frag);
  }
});

mapManyConfig = MapManyConfig(method: bufferIndirection);
massiveConfig = MassiveClassifyConfig(
         gridWidth: 16,
         gridHeight: 16,
         batchSize: 512 );
tileConfig = MassiveClassifyConfig(
         gridWidth: 16,
         gridHeight: 16,
         batchSize: 512 );
mapConfig = MapConfig( buffer: false
            order: sequential );
mapConfig1 = MapConfig( buffer: false,
         order: sequential );
launchConfig = LaunchConfig();
